home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / vms-vi-2 / part10 < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  39.8 KB

  1. Path: xanth!mcnc!gatech!bloom-beacon!bu-cs!mirror!necntc!ncoast!allbery
  2. From: gregg@a.cs.okstate.edu (Gregg Wonderly)
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i101: TPUVI for VMS part 10 of 17
  5. Message-ID: <8809212105.AA09560@uunet.UU.NET>
  6. Date: 27 Sep 88 01:55:35 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: gregg@a.cs.okstate.edu (Gregg Wonderly)
  9. Lines: 1504
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 4, Issue 101
  13. Submitted-by: "Gregg Wonderly" <gregg@a.cs.okstate.edu>
  14. Archive-name: vms-vi-2/Part10
  15.  
  16. $ WRITE SYS$OUTPUT "Creating ""VI.6"""
  17. $ CREATE VI.6
  18. $ DECK/DOLLARS=$$EOD$$
  19.         ELSE
  20.             IF (vi$wrap_scan = 1) THEN
  21.                 POSITION (BEGINNING_OF (CURRENT_BUFFER));
  22.             ENDIF;
  23.         ENDIF;
  24.     ELSE
  25.         prompt := "?" + vi$search_string;
  26.         SET (REVERSE, CURRENT_BUFFER);
  27.         IF (MARK (NONE) <> BEGINNING_OF (CURRENT_BUFFER)) THEN
  28.             IF (SUBSTR (prompt, 1, 3) = "?\<") THEN
  29.                 MOVE_HORIZONTAL (-2);
  30.             ELSE
  31.                 MOVE_HORIZONTAL (-1);
  32.             ENDIF;
  33.         ELSE
  34.             IF (vi$wrap_scan = 1) THEN
  35.                 POSITION (END_OF (CURRENT_BUFFER));
  36.             ENDIF;
  37.         ENDIF;
  38.     ENDIF;
  39.  
  40.     MESSAGE (prompt);
  41.  
  42.     ! On success then return the position we moved to.
  43.  
  44.     cnt := vi$cur_active_count;
  45.     LOOP
  46.         where := vi$find_str (vi$search_string, 0, 0);
  47.         EXITIF (where = 0);
  48.         POSITION (BEGINNING_OF (where));
  49.         IF (CURRENT_DIRECTION = FORWARD) THEN
  50.             MOVE_HORIZONTAL (1);
  51.         ELSE
  52.             MOVE_HORIZONTAL (-1);
  53.         ENDIF;
  54.         cnt := cnt - 1;
  55.         EXITIF cnt = 0;
  56.     ENDLOOP;
  57.  
  58.     IF (where = 0) THEN
  59.         vi$info ("String not found");
  60.     ELSE
  61.         POSITION (BEGINNING_OF (where));
  62.         bpos := MARK (NONE);
  63.         POSITION (END_OF (where));
  64.         vi$find_rng := CREATE_RANGE (bpos, MARK(NONE), BOLD);
  65.         MESSAGE ("");
  66.     ENDIF;
  67.  
  68.     POSITION (pos);
  69.     RETURN (where);
  70. ENDPROCEDURE;
  71.  
  72. !
  73. !   This procedure can be used to find a string of text (using RE's).
  74. !   The current direction of the BUFFER is used to determine which way
  75. !   the search goes.  'replace' is used by the replace code to indicate
  76. !   that wrap scan should be performed.
  77. !
  78. PROCEDURE vi$find_str (sstr, replace, do_parens)
  79.     LOCAL
  80.         pos,
  81.         new_pat,
  82.         start,
  83.         where;
  84.  
  85.     ON_ERROR
  86.     ENDON_ERROR;
  87.  
  88.     pos := MARK (NONE);
  89.     vi$paren_cnt := 0;
  90.     IF vi$magic THEN
  91.         new_pat := vi$re_pattern_gen (sstr, vi$paren_cnt, do_parens);
  92.     ELSE
  93.         new_pat := vi$pattern_gen (sstr);
  94.     ENDIF;
  95.  
  96.     IF (new_pat <> 0) THEN
  97.         EXECUTE (COMPILE ("vi$_find_pat := " + new_pat));
  98.         where := SEARCH (vi$_find_pat, CURRENT_DIRECTION, vi$ignore_case);
  99.         IF (where = 0) AND (vi$wrap_scan = 1) AND (replace = 0) THEN
  100.             IF (CURRENT_DIRECTION = FORWARD) THEN
  101.                 POSITION (BEGINNING_OF (CURRENT_BUFFER));
  102.             ELSE
  103.                 POSITION (END_OF (CURRENT_BUFFER));
  104.             ENDIF;
  105.             where := SEARCH (vi$_find_pat, CURRENT_DIRECTION, vi$ignore_case);
  106.         ENDIF;
  107.     ELSE
  108.         where := 0;
  109.     ENDIF;
  110.  
  111.     IF (where <> 0) AND (vi$in_ws) THEN
  112.         POSITION (BEGINNING_OF (where));
  113.         IF (CURRENT_OFFSET <> 0) OR
  114.                                 (INDEX (vi$_ws, CURRENT_CHARACTER) <> 0) THEN
  115.             MOVE_HORIZONTAL (1);
  116.         ENDIF;
  117.         start := MARK (NONE);
  118.         POSITION (END_OF (where));
  119.         IF (CURRENT_OFFSET <> LENGTH (CURRENT_LINE)) THEN
  120.             MOVE_HORIZONTAL (-1);
  121.         ENDIF;
  122.         where := CREATE_RANGE (start, MARK (NONE), NONE);
  123.         POSITION (pos);
  124.     ENDIF;
  125.     RETURN (where);
  126. ENDPROCEDURE;
  127.  
  128. !
  129. !   Generate a TPU pattern string, not using RE's, i.e. :set nomagic is
  130. !   in effect when this routine is used.
  131. !
  132. PROCEDURE vi$pattern_gen (pat)
  133.  
  134.     LOCAL
  135.         first,      ! First pattern to be done
  136.         part_pat,
  137.         chno,
  138.         startchar,
  139.         haveany,
  140.         regular,
  141.         tstr,
  142.         endchar,
  143.         str_pat,
  144.         cur_pat,    ! The current pattern to be extracted
  145.         cur_char,   ! The current character in the regular
  146.                     ! expression being examined
  147.         new_pat,    ! The output pattern
  148.         pos;        ! The position within the regular
  149.                     ! expression string that we are examining
  150.                     ! currently
  151.  
  152.     IF (INDEX (pat, "$") <> 0) OR (INDEX (pat, "^") <> 0) THEN
  153.         new_pat := "";
  154.     ELSE
  155.         new_pat := '"'+pat+'"';
  156.         RETURN (new_pat);
  157.     ENDIF;
  158.  
  159.     pos := 1;
  160.  
  161.     IF SUBSTR (pat, pos, 1) = "^" THEN
  162.         IF LENGTH (pat) > 1 THEN
  163.             new_pat := "line_begin & '";
  164.         ELSE
  165.             new_pat := "line_begin";
  166.         ENDIF;
  167.         pos := pos + 1;
  168.     ENDIF;
  169.  
  170.     LOOP
  171.         EXITIF (pos > LENGTH (pat));
  172.  
  173.         regular := 0;
  174.         cur_pat := "";
  175.         cur_char := substr (pat, pos, 1);
  176.  
  177.         IF (cur_char = "$") AND (pos+1 >= LENGTH (pat)) THEN
  178.             IF pos <> 1 THEN
  179.                 cur_pat := "' & line_end";
  180.             ELSE
  181.                 cur_pat := "line_end";
  182.             ENDIF;
  183.         ELSE
  184.             cur_pat := cur_char;
  185.             regular := 1;
  186.         ENDIF;
  187.  
  188.         IF (regular) THEN
  189.             new_pat := new_pat + cur_pat;
  190.         ELSE
  191.             IF new_pat = "" THEN
  192.                 new_pat := cur_pat;
  193.             ELSE
  194.                 new_pat := new_pat + "&" + cur_pat;
  195.             ENDIF;
  196.         ENDIF;
  197.  
  198.         pos := pos + 1;
  199.  
  200.     ENDLOOP;
  201.  
  202.     IF (regular) THEN
  203.         new_pat := new_pat + "'";
  204.     ENDIF;
  205.     RETURN (new_pat);
  206. ENDPROCEDURE;
  207. !
  208. !
  209. ! TPU pattern generator.  Generates a pattern string from the passed
  210. ! RE string.  The function is used when :set magic is in effect.
  211. !
  212. PROCEDURE vi$re_pattern_gen (pat, paren_cnt, do_parens)
  213.  
  214.     LOCAL
  215.         first,      ! First pattern to be done
  216.         part_pat,
  217.         chno,
  218.         startchar,
  219.         haveany,
  220.         regular,
  221.         tstr,
  222.         endchar,
  223.         pat_str,
  224.         str_pat,
  225.         cur_pat,    ! The current pattern to be extracted
  226.         cur_char,   ! The current character in the regular
  227.                     ! expression being examined
  228.         new_pat,    ! The output pattern
  229.         in_ws,
  230.         pos;        ! The position within the regular
  231.                     ! expression string that we are examining
  232.                     ! currently
  233.  
  234.     vi$in_ws := 0;
  235.     IF ((INDEX (pat, "$") <> 0) OR (INDEX (pat, "[") <> 0) OR
  236.                     (INDEX (pat, "^") <> 0) OR (INDEX (pat, ".") <> 0) OR
  237.                         (INDEX (pat, "*") <> 0) OR (INDEX (pat, "\") <> 0) OR
  238.                         (INDEX (pat, '"') <> 0)) THEN
  239.         new_pat := "";
  240.     ELSE
  241.         new_pat := '"'+pat+'"';
  242.         RETURN (new_pat);
  243.     ENDIF;
  244.  
  245.     in_ws := 0;
  246.     pos := 1;
  247.  
  248.     IF SUBSTR (pat, pos, 1) = "^" THEN
  249.         new_pat := "line_begin";
  250.         pos := pos + 1;
  251.     ENDIF;
  252.  
  253.     LOOP
  254.         EXITIF (pos > LENGTH (pat));
  255.  
  256.         regular := 0;
  257.         cur_pat := "";
  258.         cur_char := substr (pat, pos, 1);
  259.         pat_str := "";
  260.  
  261.         IF (cur_char = "^") THEN
  262.             vi$info ("^ found in the middle of a line, use \ to escape it!");
  263.             RETURN (0);
  264.         ENDIF;
  265.  
  266.         IF (cur_char = "$") THEN
  267.             IF (pos >= LENGTH (pat)) THEN
  268.                 cur_pat := "line_end";
  269.             ELSE
  270.                 vi$info ("$ found before end of string");
  271.                 RETURN (0);
  272.             ENDIF;
  273.         ELSE
  274.             IF cur_char = "[" THEN
  275.                 pos := pos + 1;
  276.  
  277.                 IF SUBSTR (pat, pos, 1) = "^" THEN
  278.                     pos := pos + 1;
  279.                     part_pat := "notany('";
  280.                 ELSE
  281.                     part_pat := "any('";
  282.                 ENDIF;
  283.  
  284.                 LOOP
  285.                     EXITIF pos > LENGTH (pat);
  286.                     EXITIF SUBSTR (pat, pos, 1) = "]";
  287.  
  288.                     IF SUBSTR (pat, pos, 1) = "\" THEN
  289.                         pos := pos + 1;
  290.                         IF pos > LENGTH (pat) THEN
  291.                             vi$info ("Missing character after \");
  292.                             RETURN (0);
  293.                         ENDIF;
  294.                     ENDIF;
  295.  
  296.                     startchar := SUBSTR (pat, pos, 1);
  297.                     pat_str := pat_str + startchar;
  298.                     IF startchar = "'" THEN
  299.                         pat_str := pat_str + "'";
  300.                     ENDIF;
  301.  
  302.                     IF (SUBSTR (pat, pos+1, 1) = '-') THEN
  303.                         pos := pos + 2;
  304.                         IF (pos >= LENGTH (pat)) THEN
  305.                             vi$info ("Missing character after '-'");
  306.                             RETURN (0);
  307.                         ENDIF;
  308.  
  309.                         endchar := SUBSTR (pat, pos, 1);
  310.  
  311.                         chno := 1;
  312.                         LOOP
  313.                             EXITIF (ASCII(chno) = startchar);
  314.                             chno := chno + 1;
  315.                         ENDLOOP;
  316.  
  317.                         LOOP
  318.                             chno := chno + 1;
  319.                             IF (chno > 255) THEN
  320.                                 vi$info (
  321.                                     "Invalid character sequence for '-'");
  322.                                 RETURN (0);
  323.                             ENDIF;
  324.  
  325.                             EXITIF (ASCII (chno-1) = endchar);
  326.                             pat_str := pat_str + ASCII (chno);
  327.                             IF ASCII (chno) = "'" THEN
  328.                                 pat_str := pat_str + "'";
  329.                             ENDIF;
  330.                         ENDLOOP;
  331.                     ENDIF;
  332.                     pos := pos + 1;
  333.                 ENDLOOP;
  334.  
  335.                 IF pat_str = "" THEN
  336.                     vi$info ("No text found between []");
  337.                     RETURN (0);
  338.                 ENDIF;
  339.  
  340.                 IF (SUBSTR (pat, pos+1, 1) = "*") THEN
  341.                     IF (part_pat = "notany('") THEN
  342.                         cur_pat := cur_pat + "(scan('"+pat_str+"')|"""")";
  343.                     ELSE
  344.                         cur_pat := cur_pat + "(span('"+pat_str+"')|"""")";
  345.                     ENDIF;
  346.                     pos := pos + 1;
  347.                 ELSE
  348.                     cur_pat := part_pat + pat_str + "')";
  349.                 ENDIF;
  350.             ELSE
  351.  
  352.                 tstr := '"';
  353.                 haveany := 0;
  354.                 regular := 1;
  355.  
  356.                 LOOP
  357.                     cur_char := SUBSTR (pat, pos, 1);
  358.                     EXITIF (cur_char = "^") OR (cur_char = "[") OR
  359.                             (cur_char = "$");
  360.                     EXITIF (pos > LENGTH (pat));
  361.  
  362.                     IF cur_char = "\" THEN
  363.                         pos := pos + 1;
  364.                         startchar := SUBSTR (pat, pos, 1);
  365.                         IF (do_parens) THEN
  366.                             IF (startchar = "(") THEN
  367.                                 paren_cnt := paren_cnt + 1;
  368.  
  369.                                 IF tstr = '"' THEN
  370.                                     tstr := '""@o'+STR(paren_cnt)+'&"';
  371.                                 ELSE
  372.                                     tstr := tstr + '"@o'+STR(paren_cnt)+'&"';
  373.                                 ENDIF;
  374.                             ELSE
  375.                                 IF (startchar = ")") THEN
  376.                                     IF (paren_cnt = 0) THEN
  377.                                         vi$info (
  378.                                             FAO ("No previous ""\("" near: !AS",
  379.                                             SUBSTR (pat, pos, LENGTH(pat)-pos))
  380.                                         );
  381.                                         RETURN (0);
  382.                                     ENDIF;
  383.  
  384.                                     IF tstr = '"' THEN
  385.                                         tstr := '""@p'+STR(paren_cnt)+'&"';
  386.                                     ELSE
  387.                                         tstr := tstr + '"@p' +
  388.                                                     STR(paren_cnt)+'&"';
  389.                                     ENDIF;
  390.                                 ELSE
  391.                                     IF (startchar = "<") THEN
  392.                                         in_ws := 1;
  393.                                         vi$in_ws := 1;
  394.                                         tstr := tstr +
  395.                                             '"&(line_begin | any (vi$_ws))&"';
  396.                                     ELSE
  397.                                         IF (startchar = ">") THEN
  398.                                             in_ws := 0;
  399.                                             tstr := tstr +
  400.                                                 '"&(line_end | any (vi$_ws))&"';
  401.                                         ELSE
  402.                                             tstr := tstr + SUBSTR (pat, pos, 1);
  403.                                         ENDIF;
  404.                                     ENDIF;
  405.                                 ENDIF;
  406.                             ENDIF;
  407.                         ELSE
  408.                             IF (startchar = "<") THEN
  409.                                 in_ws := 1;
  410.                                 vi$in_ws := 1;
  411.                                 tstr := tstr +
  412.                                     '"&(line_begin | any (vi$_ws))&"';
  413.                             ELSE
  414.                                 IF (startchar = ">") THEN
  415.                                     in_ws := 0;
  416.                                     tstr := tstr
  417.                                         + '"&(line_end | any (vi$_ws))&"';
  418.                                 ELSE
  419.                                     tstr := tstr + startchar;
  420.                                 ENDIF;
  421.                             ENDIF;
  422.                         ENDIF;
  423.                     ELSE
  424.                         IF (cur_char = ".") THEN
  425.                             cur_char := "longer_than_1";
  426.                         ENDIF;
  427.  
  428.                         IF (SUBSTR (pat, pos+1, 1) = '*') THEN
  429.                             pos := pos + 1;
  430.  
  431.                             IF (LENGTH (cur_char) > 1) THEN
  432.                                 cur_pat := "span(vi$pch)";
  433.                             ELSE
  434.                                 cur_pat := "span('"+cur_char+"')";
  435.                             ENDIF;
  436.                             tstr := tstr+'"&'+cur_pat+'&"';
  437.                             haveany := 0;
  438.                         ELSE
  439.                             IF (LENGTH (cur_char) > 1) THEN
  440.                                 IF (haveany) THEN
  441.                                     tstr := tstr +'"&'+"arb(1)"+'&"';
  442.                                     haveany := 0;
  443.                                 ELSE
  444.                                     IF (LENGTH (tstr)>0) and (tstr <> '"') THEN
  445.                                         tstr := tstr +'"&'+"arb(1)"+'&"';
  446.                                     ELSE
  447.                                         tstr := "arb(1)"+'&"';
  448.                                     ENDIF
  449.                                 ENDIF;
  450.                             ELSE
  451.                                 IF (cur_char = """") THEN
  452.                                     tstr := tstr + '""';
  453.                                     haveany := haveany + 2;
  454.                                 ELSE
  455.                                     tstr := tstr + cur_char;
  456.                                     haveany := haveany + 1;
  457.                                 ENDIF;
  458.                             ENDIF;
  459.                         ENDIF;
  460.                     ENDIF;
  461.                     pos := pos + 1;
  462.                 ENDLOOP;
  463.                 cur_pat := tstr + '"';
  464.                 pos := pos - 1;
  465.             ENDIF;
  466.         ENDIF;
  467.  
  468.         IF (regular) THEN
  469.             IF new_pat = "" THEN
  470.                 new_pat := cur_pat;
  471.             ELSE
  472.                 IF (LENGTH (tstr) > 1) THEN
  473.                     new_pat := new_pat + "&" + cur_pat;
  474.                 ENDIF;
  475.             ENDIF;
  476.         ELSE
  477.             IF new_pat = "" THEN
  478.                 new_pat := cur_pat;
  479.             ELSE
  480.                 new_pat := new_pat + "&" + cur_pat;
  481.             ENDIF;
  482.         ENDIF;
  483.         pos := pos + 1;
  484.  
  485.     ENDLOOP;
  486.  
  487.     IF (in_ws) THEN
  488.         vi$info ("Missing \> in pattern!");
  489.         RETURN (0);
  490.     ENDIF;
  491.  
  492.     RETURN (new_pat);
  493. ENDPROCEDURE;
  494.  
  495. !
  496. !   Match brackets when '%' is typed.
  497. !
  498. PROCEDURE vi$_match_brackets
  499.     vi$beep_position (vi$match_brackets, 1, 1);
  500. ENDPROCEDURE;
  501.  
  502. !
  503. !   Perform the actual match bracket operation.
  504. !
  505. PROCEDURE vi$match_brackets
  506.     LOCAL
  507.         newpos,
  508.         ind_pos,
  509.         found,
  510.         cur_ch,
  511.         cur_dir,
  512.         pos;
  513.  
  514.     ON_ERROR
  515.         IF ERROR = TPU$_CONTROLC THEN
  516.             vi$beep;
  517.             vi$pasthru_on;
  518.             RETURN (0);
  519.         ENDIF;
  520.     ENDON_ERROR;
  521.  
  522.     found := 1;
  523.     MESSAGE ("");
  524.     pos := MARK (NONE);
  525.     cur_ch := CURRENT_CHARACTER;
  526.     ind_pos := INDEX (vi$bracket_chars, cur_ch);
  527.  
  528.     IF (ind_pos = 0) THEN
  529.         newpos := SEARCH (ANCHOR & SCAN (")") & ARB (1), FORWARD, EXACT);
  530.         found := 0;
  531.         IF newpos <> 0 THEN
  532.             found := 1;
  533.             IF vi$in_show_match = 0 THEN
  534.                 vi$old_place := pos;
  535.             ENDIF;
  536.             POSITION (END_OF (newpos));
  537.             RETURN (vi$retpos (pos));
  538.         ELSE
  539.             POSITION (pos);
  540.             RETURN (0);
  541.         ENDIF;
  542.     ENDIF;
  543.  
  544.     IF ((ind_pos/2)*2 <> ind_pos) THEN
  545.         cur_dir := FORWARD;
  546.     ELSE
  547.         cur_dir := REVERSE;
  548.     ENDIF;
  549.  
  550.     SET (TIMER, ON, "Searching...");
  551.     newpos := vi$do_match (CURRENT_CHARACTER, cur_dir, 0);
  552.     SET (TIMER, OFF);
  553.  
  554.     IF (GET_INFO (newpos, "TYPE") = MARKER) THEN
  555.         RETURN (vi$retpos (pos));
  556.     ELSE
  557.         IF (newpos = 0) AND NOT (vi$in_show_match) THEN
  558.             vi$info ("No matching bracket");
  559.         ENDIF;
  560.         POSITION (pos);
  561.     ENDIF;
  562.     RETURN (0);
  563. ENDPROCEDURE;
  564. !
  565. !
  566. !  This procedure knows how to traverse nested brackets to find the matching
  567. !  bracket.  It takes the character that the cursor is positioned on, and
  568. !  finds the matching one.  It recognizes '{}', '[]', '()' pairs.
  569. !
  570. PROCEDURE vi$do_match (bracket, cur_dir, level)
  571.  
  572.     LOCAL
  573.         dgrp,
  574.         dest_char,
  575.         sel_reg,
  576.         ind_pos,
  577.         next_pos,
  578.         possibles,
  579.         cur_ch;
  580.  
  581.     ON_ERROR
  582.         RETURN (0);
  583.     ENDON_ERROR;
  584.  
  585.     IF level > 30 THEN
  586.         vi$info ("Too many nested levels");
  587.         RETURN (-1);
  588.     ENDIF;
  589.  
  590.     ! Identify the desired search direction based on the character.
  591.  
  592.     ind_pos := INDEX (vi$bracket_chars, bracket);
  593.     dest_char := SUBSTR ("}{)(][", ind_pos, 1);
  594.  
  595.     IF cur_dir = FORWARD THEN
  596.         MOVE_HORIZONTAL (1);
  597.     ENDIF;
  598.  
  599.     dgrp := bracket + dest_char;
  600.     LOOP
  601.         sel_reg := SEARCH (ANY (dgrp), cur_dir, EXACT);
  602.  
  603.         IF sel_reg = 0 THEN
  604.             RETURN (0);
  605.         ENDIF;
  606.  
  607.         POSITION (BEGINNING_OF (sel_reg));
  608.  
  609.         IF (CURRENT_CHARACTER = dest_char) THEN
  610.             RETURN (MARK (NONE));
  611.         ELSE
  612.             IF (((INDEX ("([{", CURRENT_CHARACTER) <> 0) AND
  613.                             (cur_dir = FORWARD)) OR
  614.                     ((INDEX (")}]", CURRENT_CHARACTER) <> 0) AND
  615.                             (cur_dir = REVERSE))) THEN
  616.  
  617.                 IF (INDEX (vi$bracket_chars, CURRENT_CHARACTER)-1)/2 <=
  618.                             (INDEX (vi$bracket_chars, dest_char)-1)/2 THEN
  619.  
  620.                     next_pos := vi$do_match (CURRENT_CHARACTER,
  621.                                                             cur_dir, level+1);
  622.  
  623.                     IF (next_pos <> 0) AND (next_pos <> -1) THEN
  624.                         POSITION (next_pos);
  625.                     ELSE
  626.                         RETURN (next_pos);
  627.                     ENDIF;
  628.                 ENDIF;
  629.             ELSE
  630.                 IF (INDEX (vi$bracket_chars, CURRENT_CHARACTER) = 0) THEN
  631.                     vi$info ("Unknown bracket character: '"+
  632.                                                     CURRENT_CHARACTER+"'");
  633.                     RETURN (-1);
  634.                 ENDIF;
  635.             ENDIF;
  636.  
  637.             IF cur_dir = FORWARD THEN
  638.                 MOVE_HORIZONTAL (1);
  639.             ENDIF;
  640.         ENDIF;
  641.     ENDLOOP;
  642. ENDPROCEDURE;
  643.  
  644. !
  645. !   Move to the top line of the window when 'H' is pressed.
  646. !
  647. PROCEDURE vi$home
  648.     POSITION (vi$to_home);
  649. ENDPROCEDURE;
  650.  
  651. !
  652. !   Perform the actual movement for the 'H' command and return the marker.
  653. !
  654. PROCEDURE vi$to_home
  655.  
  656.     LOCAL
  657.         pos;
  658.  
  659.     ON_ERROR
  660.         ! Ignore attempt to move beyond end of buffer errors.
  661.     ENDON_ERROR;
  662.  
  663.     pos := MARK (NONE);
  664.     MOVE_VERTICAL ( GET_INFO (CURRENT_WINDOW, "VISIBLE_TOP") -
  665.                     GET_INFO (CURRENT_WINDOW, "CURRENT_ROW"));
  666.  
  667.     vi$yank_mode := VI$LINE_MODE;
  668.     RETURN (vi$retpos(pos));
  669. ENDPROCEDURE
  670.  
  671. !
  672. !   Position the cursor into the middle of the current window when 'M' is
  673. !   pressed.
  674. !
  675. PROCEDURE vi$middle
  676.     POSITION (vi$to_middle);
  677. ENDPROCEDURE;
  678.  
  679. !
  680. !   Perform the actual movement of the 'M' command.
  681. !
  682. PROCEDURE vi$to_middle
  683.  
  684.     LOCAL
  685.         len,
  686.         cur,
  687.         top,
  688.         pos;
  689.  
  690.     ON_ERROR
  691.         ! Ignore attempt to move beyond end of buffer errors.
  692.     ENDON_ERROR;
  693.  
  694.     pos := MARK (NONE);
  695.  
  696.     len := GET_INFO (CURRENT_WINDOW, "VISIBLE_LENGTH");
  697.     cur := GET_INFO (CURRENT_WINDOW, "CURRENT_ROW");
  698.     top := GET_INFO (CURRENT_WINDOW, "VISIBLE_TOP");
  699.  
  700.     MOVE_VERTICAL ((top + len/2 - 1) - cur);
  701.  
  702.     vi$yank_mode := VI$LINE_MODE;
  703.     RETURN (vi$retpos(pos));
  704. ENDPROCEDURE;
  705.  
  706. !
  707. !   Move the the last line of the current window when 'L' is pressed.
  708. !
  709. PROCEDURE vi$last
  710.     POSITION (vi$to_last);
  711. ENDPROCEDURE;
  712.  
  713. !
  714. !   Perform the actual movement associated with the 'L' command.
  715. !
  716. PROCEDURE vi$to_last
  717.  
  718.     LOCAL
  719.         pos;
  720.  
  721.     ON_ERROR
  722.         ! Ignore attempt to move beyond end of buffer errors.
  723.     ENDON_ERROR;
  724.  
  725.     pos := MARK (NONE);
  726.     MOVE_VERTICAL ( GET_INFO (CURRENT_WINDOW, "VISIBLE_BOTTOM") -
  727.                     GET_INFO (CURRENT_WINDOW, "CURRENT_ROW"));
  728.  
  729.     vi$yank_mode := VI$LINE_MODE;
  730.     RETURN (vi$retpos (pos));
  731. ENDPROCEDURE
  732.  
  733. !
  734. !   Move to the end of the current line when '$' is pressed.
  735. !
  736. PROCEDURE vi$_eol
  737.     POSITION (vi$eol);
  738. ENDPROCEDURE;
  739.  
  740. !
  741. !   Perform the actual movement associated with the '$' command.
  742. !
  743. PROCEDURE vi$eol
  744.     LOCAL
  745.         cnt,
  746.         pos;
  747.  
  748.     ON_ERROR
  749.         POSITION (pos);
  750.         vi$active_count := 0;
  751.         RETURN (0);
  752.     ENDON_ERROR;
  753.  
  754.     pos := MARK (NONE);
  755.     POSITION (LINE_BEGIN);
  756.     cnt := vi$active_count;
  757.     IF cnt = 0 THEN
  758.         cnt := 1;
  759.     ENDIF;
  760.     MOVE_VERTICAL (cnt - 1);
  761.     IF (CURRENT_CHARACTER = "") THEN
  762.         RETURN (0);
  763.     ENDIF;
  764.  
  765.     POSITION (LINE_END);
  766.     vi$check_rmarg;
  767.  
  768.     IF (vi$active_count > 0) THEN
  769.         vi$yank_mode := VI$LINE_MODE;
  770.     ELSE
  771.         vi$yank_mode := VI$IN_LINE_MODE;
  772.     ENDIF;
  773.     vi$active_count := 0;
  774.     RETURN (vi$retpos (pos));
  775. ENDPROCEDURE;
  776.  
  777. !
  778. !   Move the first non-blank character of the line when '^' is typed.
  779. !
  780. PROCEDURE vi$_bol (use_cur_active)
  781.     vi$beep_position (vi$first_no_space (use_cur_active), 0, 1);
  782. ENDPROCEDURE;
  783.  
  784. !
  785. !   Move the beginning of the line when '0' is typed.
  786. !
  787. PROCEDURE vi$fol
  788.     LOCAL
  789.         pos;
  790.  
  791.     pos := MARK (NONE);
  792.     POSITION (LINE_BEGIN);
  793.     vi$yank_mode := VI$IN_LINE_MODE;
  794.     vi$new_offset := 1;
  795.     RETURN (vi$retpos (pos));
  796. ENDPROCEDURE;
  797.  
  798. !
  799. !   Move the the location searched for.
  800. !
  801. PROCEDURE vi$_search (direction)
  802.     LOCAL
  803.         opos,
  804.         pos;
  805.  
  806.     opos := MARK (NONE);
  807.     pos := vi$search(direction);
  808.  
  809.     IF (vi$beep_position (pos, 1, 0) <> 0) THEN
  810.         POSITION (opos);
  811.         vi$pos_in_middle (pos);
  812.     ENDIF;
  813. ENDPROCEDURE;
  814.  
  815. !
  816. !   Move to the next location of the string previously searched for.
  817. !
  818. PROCEDURE vi$_search_next (direction)
  819.     LOCAL
  820.         opos,
  821.         pos;
  822.  
  823.     opos := MARK(NONE);
  824.     pos := vi$search_next(direction);
  825.  
  826.     IF (vi$beep_position (pos, 1, 0) <> 0) THEN
  827.         POSITION (opos);
  828.         vi$pos_in_middle (pos);
  829.     ENDIF;
  830. ENDPROCEDURE;
  831.  
  832. !
  833. !   Repeat the last 't' or 'f' command backwards.
  834. !
  835. PROCEDURE vi$_repeat_torf_back
  836.     vi$beep_position (vi$repeat_torf_back, 0, 1);
  837. ENDPROCEDURE
  838.  
  839. !
  840. !   Repeat the last 't' or 'f' command.
  841. !
  842. PROCEDURE vi$_repeat_torf
  843.     vi$beep_position (vi$repeat_torf, 0, 1);
  844. ENDPROCEDURE
  845.  
  846. !
  847. !   Return the location found by repeating the last 't', 'f', 'T' or 'F'
  848. !   command backwards.
  849. !
  850. PROCEDURE vi$repeat_torf_back
  851.     LOCAL
  852.         ch,
  853.         old_func,
  854.         back_func;
  855.  
  856.     IF vi$last_s_func = 0 THEN
  857.         RETURN (0);
  858.     ENDIF;
  859.  
  860.     old_func := vi$last_s_func;
  861.     IF (vi$last_s_func = "vi$back_find_char") THEN
  862.         back_func := "vi$find_char";
  863.     ENDIF;
  864.  
  865.     IF (vi$last_s_func = "vi$find_char") THEN
  866.         back_func := "vi$back_find_char";
  867.     ENDIF;
  868.  
  869.     IF (vi$last_s_func = "vi$back_to_char") THEN
  870.         back_func := "vi$to_char";
  871.     ENDIF;
  872.  
  873.     IF (vi$last_s_func = "vi$to_char") THEN
  874.         back_func := "vi$back_to_char";
  875.     ENDIF;
  876.  
  877.     vi$global_var := 0;
  878.     ch := vi$last_s_char;
  879.     IF (ch = "'") THEN
  880.         ch := "''";
  881.     ENDIF;
  882.  
  883.     EXECUTE (COMPILE (
  884.         "vi$global_var := " + back_func + "('"+ ch + "')"));
  885.     vi$last_s_func := old_func;
  886.     RETURN (vi$global_var);
  887. ENDPROCEDURE
  888.  
  889. !
  890. !   Return the location found by repeating the last 't', 'f', 'T' or 'F'
  891. !   command.
  892. !
  893. PROCEDURE vi$repeat_torf
  894.  
  895.     LOCAL
  896.         ch;
  897.  
  898.     vi$global_var := 0;
  899.     ch := vi$last_s_char;
  900.     IF (ch = "'") THEN
  901.         ch := "''";
  902.     ENDIF;
  903.     IF (vi$last_s_func <> 0) THEN
  904.         EXECUTE (COMPILE (
  905.             "vi$global_var := " + vi$last_s_func + "('"+ ch + "')"));
  906.     ELSE
  907.         vi$beep;
  908.     ENDIF;
  909.     RETURN (vi$global_var);
  910. ENDPROCEDURE
  911.  
  912. !
  913. !   Return the value of a positive integer that is represented as a string.
  914. !   If the string is not a valid integer, then -1 is retured.
  915. !
  916. PROCEDURE vi$number_from_string (str_num)
  917.     ON_ERROR
  918.         RETURN (-1);
  919.     ENDON_ERROR;
  920.  
  921.     RETURN (INT (str_num));
  922. ENDPROCEDURE;
  923.  
  924. !
  925. !   Move to the line indicated by 'line_no', and return the marker that
  926. !   indicates the beginning of that line.
  927. !
  928. PROCEDURE vi$mark_line (line_no)
  929.  
  930.     LOCAL
  931.         pos;
  932.  
  933.     ON_ERROR
  934.         POSITION (pos);
  935.         RETURN (0);
  936.     ENDON_ERROR;
  937.  
  938.     pos := MARK (NONE);
  939.     POSITION (BEGINNING_OF (CURRENT_BUFFER));
  940.     MOVE_VERTICAL (line_no - 1);
  941.     RETURN (vi$retpos (pos));
  942. ENDPROCEDURE;
  943.  
  944. !
  945. !   Perform an EX mode command after a ':' is typed.
  946. !
  947. PROCEDURE vi$ex_mode
  948.     LOCAL
  949.         cmd_str;
  950.  
  951.     IF (vi$read_a_line (":", cmd_str) <> 0) and (cmd_str <> "") THEN
  952.         vi$do_cmd_line (cmd_str);
  953.     ENDIF;
  954. ENDPROCEDURE;
  955.  
  956. !
  957. !
  958. !
  959. PROCEDURE vi$read_a_line (prompt, cmd_str)
  960.     LOCAL
  961.         cmd_idx,
  962.         addch,
  963.         ch,
  964.         did_ctl_v,
  965.         win,
  966.         pos;
  967.  
  968.     win := CURRENT_WINDOW;
  969.     pos := MARK (NONE);
  970.  
  971.     POSITION (END_OF (command_buffer));
  972.     MAP (command_window, command_buffer);
  973.     COPY_TEXT (prompt);
  974.     SET (OVERSTRIKE, CURRENT_BUFFER);
  975.  
  976.     cmd_str := "";
  977.     cmd_idx := 0;
  978.     LOOP
  979.         vi$update (CURRENT_WINDOW);
  980.         ch := vi$read_a_key;
  981.  
  982.         did_ctl_v := 0;
  983.         IF ch = CTRL_V_KEY THEN
  984.             COPY_TEXT ("^");
  985.             did_ctl_v := 1;
  986.             MOVE_HORIZONTAL (-1);
  987.             vi$update (CURRENT_WINDOW);
  988.             ch := vi$read_a_key;
  989.             ERASE_CHARACTER (1);
  990.         ENDIF;
  991.  
  992.         EXITIF ((ch = RET_KEY) OR (ch = F11)) AND (did_ctl_v = 0);
  993.  
  994.         IF (ch = RET_KEY) THEN ch := CTRL_M_KEY; ENDIF;
  995.         IF (ch = F12) THEN ch := CTRL_H_KEY; ENDIF;
  996.         IF (ch = F11) THEN ch := KEY_NAME (ASCII (27)); ENDIF;
  997.  
  998.         IF ((ch = DEL_KEY) OR (ch = CTRL_H_KEY)) AND (did_ctl_v = 0) THEN
  999.             IF cmd_idx = 0 THEN
  1000.                 UNMAP (command_window);
  1001.                 UNMAP (message_window);
  1002.                 MAP (message_window, message_buffer);
  1003.                 POSITION (win);
  1004.                 POSITION (pos);
  1005.                 RETURN (0);
  1006.             ENDIF;
  1007.             ch := SUBSTR (cmd_str, cmd_idx, 1);
  1008.             cmd_idx := cmd_idx - 1;
  1009.             IF (INDEX (vi$_ctl_chars, ch) <> 0) THEN
  1010.                 MOVE_HORIZONTAL (-2);
  1011.             ELSE
  1012.                 MOVE_HORIZONTAL (-1);
  1013.             ENDIF;
  1014.             cmd_str := SUBSTR (cmd_str, 1, cmd_idx);
  1015.         ELSE
  1016.             IF (INT(ch) <= INT(KEY_NAME (ASCII (31)))) AND
  1017.                                 (INT (ch) >= INT(CTRL_A_KEY)) THEN
  1018.                 IF ch = TAB_KEY THEN
  1019.                     addch := 9;
  1020.                     COPY_TEXT (ASCII(addch));
  1021.                 ELSE
  1022.                     addch := ((INT(ch) - INT(CTRL_A_KEY)) / 256) + 1;
  1023.                     COPY_TEXT ("^");
  1024.                     COPY_TEXT (ASCII (addch + 64));
  1025.                 ENDIF;
  1026.                 cmd_str := cmd_str + ASCII (addch);
  1027.                 cmd_idx := cmd_idx + 1;
  1028.                 IF ch = 27 THEN ch := F11; ENDIF;
  1029.             ELSE
  1030.                 IF (ch = UP) THEN
  1031.                     vi$next_in_cmd (cmd_str, cmd_idx, prompt, -1);
  1032.                 ELSE
  1033.                     IF (ch = DOWN) THEN
  1034.                         vi$next_in_cmd (cmd_str, cmd_idx, prompt, 1);
  1035.                     ELSE
  1036.                         COPY_TEXT (ASCII(ch));
  1037.                         cmd_str := cmd_str + ASCII (ch);
  1038.                         cmd_idx := cmd_idx + 1;
  1039.                     ENDIF;
  1040.                 ENDIF;
  1041.             ENDIF;
  1042.         ENDIF;
  1043.     ENDLOOP;
  1044.  
  1045.     ERASE_CHARACTER (LENGTH (CURRENT_LINE) - CURRENT_OFFSET);
  1046.     vi$update (CURRENT_WINDOW);
  1047.  
  1048.     IF (cmd_idx > 0) THEN
  1049.         POSITION (END_OF (command_buffer));
  1050.         LOOP
  1051.             MOVE_VERTICAL (-1);
  1052.             EXITIF (CURRENT_LINE <> prompt);
  1053.             ERASE_LINE;
  1054.         ENDLOOP;
  1055.  
  1056.         IF (CURRENT_LINE <> prompt + cmd_str) THEN
  1057.             MOVE_VERTICAL (1);
  1058.             COPY_TEXT (prompt + cmd_str);
  1059.         ENDIF;
  1060.     ENDIF;
  1061.  
  1062.     UNMAP (command_window);
  1063.     UNMAP (message_window);
  1064.     MAP (message_window, message_buffer);
  1065.  
  1066.     POSITION (win);
  1067.     POSITION (pos);
  1068.  
  1069.     RETURN (cmd_idx > 0);
  1070. ENDPROCEDURE;
  1071.  
  1072. !
  1073. !   This procedure looks from the next occurence of 'prompt' at the
  1074. !   beginning of the line, in the direction dir (1 or -1).  If prompt
  1075. !   is found, then cmd_str is set to the contents of that line, minus
  1076. !   the text of the prompt, and cmd_idx is set to the length of cmd_str.
  1077. !   The cursor is left positioned at the end of the line found, or if
  1078. !   none is found, it is not moved.
  1079. !
  1080. PROCEDURE vi$next_in_cmd (cmd_str, cmd_idx, prompt, dir)
  1081.     LOCAL
  1082.         pos,
  1083.         len;
  1084.  
  1085.     ON_ERROR
  1086.         POSITION (pos);
  1087.         RETURN;
  1088.     ENDON_ERROR;
  1089.  
  1090.     pos := MARK (NONE);
  1091.     len := LENGTH (prompt);
  1092.  
  1093.     POSITION (LINE_BEGIN);
  1094.     LOOP
  1095.         EXITIF (MARK (NONE) = BEGINNING_OF (CURRENT_BUFFER)) AND (dir = -1);
  1096.         EXITIF (MARK (NONE) = END_OF (CURRENT_BUFFER)) AND (dir = 1);
  1097.         MOVE_VERTICAL (DIR);
  1098.         IF SUBSTR (CURRENT_LINE, 1, len) = prompt THEN
  1099.             cmd_str := SUBSTR (CURRENT_LINE, len+1,
  1100.                                             LENGTH (CURRENT_LINE) - len + 1);
  1101.             cmd_idx := LENGTH (cmd_str);
  1102.             POSITION (LINE_END);
  1103.             RETURN;
  1104.         ENDIF;
  1105.     ENDLOOP;
  1106.     POSITION (pos);
  1107. ENDPROCEDURE;
  1108.  
  1109. !
  1110. !   Perform a whole series of command separated by '|'s.
  1111. !
  1112. PROCEDURE vi$do_cmd_line (cmd)
  1113.     LOCAL
  1114.         ch,
  1115.         retval,
  1116.         idx,
  1117.         strg;
  1118.  
  1119.     idx := 1;
  1120.     strg := "";
  1121.  
  1122.     LOOP
  1123.         EXITIF (idx > LENGTH (cmd));
  1124.         ch := SUBSTR (cmd, idx, 1);
  1125.         IF (ch = "|") THEN
  1126.             retval := vi$do_command (strg);
  1127.             IF (retval > 1) THEN
  1128.                 RETURN (retval);
  1129.             ENDIF;
  1130.             strg := "";
  1131.         ELSE
  1132.             IF (ch = "\") THEN
  1133.                 idx := idx + 1;
  1134.                 IF (SUBSTR (cmd, idx, 1) = "|") THEN
  1135.                     strg := strg + "|";
  1136.                 ELSE
  1137.                     strg := strg + "\" + SUBSTR (cmd, idx, 1);
  1138.                 ENDIF;
  1139.             ELSE
  1140.                 strg := strg + ch;
  1141.             ENDIF;
  1142.         ENDIF;
  1143.         idx := idx + 1;
  1144.     ENDLOOP;
  1145.  
  1146.     IF (strg <> "") THEN
  1147.         IF (vi$do_command (strg) <> 0) THEN
  1148.             RETURN (1);
  1149.         ENDIF;
  1150.     ENDIF;
  1151.     RETURN (0);
  1152. ENDPROCEDURE;
  1153.  
  1154. !
  1155. !   Perform an EX (not all are implemented) command as given in "cmd".
  1156. !
  1157. PROCEDURE vi$do_command (cmd)
  1158.     LOCAL
  1159.         rng,
  1160.         outf,
  1161.         mode,
  1162.         token_1,
  1163.         token_2,
  1164.         token_3,
  1165.         res_spec,
  1166.         start_mark,
  1167.         end_mark,
  1168.         start_line,
  1169.         end_line,
  1170.         work_range,
  1171.         whole_range,
  1172.         buf,
  1173.         spos,
  1174.         rest,
  1175.         separ,
  1176.         no_spec,
  1177.         ch,
  1178.         i,
  1179.         j,
  1180.         olen,
  1181.         bang,
  1182.         num,
  1183.         pos;
  1184.  
  1185.     olen := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT");
  1186.  
  1187.     ! Start at beginning of string and look for a range of lines.
  1188.  
  1189.     i := 1;
  1190.  
  1191.     pos := MARK (NONE);
  1192.     num := vi$get_line_spec (i, cmd);
  1193.  
  1194.     IF (num < 0) THEN
  1195.         vi$info ("search line not found!");
  1196.         POSITION (pos);
  1197.         RETURN (1);
  1198.     ENDIF;
  1199.  
  1200.     no_spec := 0;
  1201.     IF (num <= 0) THEN
  1202.         IF (vi$parse_next_ch (i, cmd, "%")) THEN
  1203.             start_line := 1;
  1204.             end_line := GET_INFO (CURRENT_BUFFER, "RECORD_COUNT");
  1205.         ELSE
  1206.             no_spec := 1;
  1207.             start_line := vi$cur_line_no;
  1208.             end_line := start_line;
  1209.         ENDIF;
  1210.     ELSE
  1211.         start_line := num;
  1212.         IF (vi$parse_next_ch (i, cmd, ",")) THEN
  1213.             num := vi$get_line_spec (i, cmd);
  1214.             IF (num < 0) THEN
  1215.                 vi$info ("Invalid line range specification!");
  1216.                 RETURN (1);
  1217.             ENDIF;
  1218.             end_line := num;
  1219.         ELSE
  1220.             end_line := start_line;
  1221.         ENDIF;
  1222.     ENDIF;
  1223.  
  1224.     POSITION (pos);
  1225.  
  1226.     work_range := 0;
  1227.     whole_range := 0;
  1228.  
  1229.     IF (start_line > end_line) THEN
  1230.         vi$info ("Bad range of lines!");
  1231.         RETURN (1);
  1232.     ENDIF;
  1233.  
  1234.     start_mark := vi$mark_line (start_line);
  1235.     end_mark := vi$mark_line (end_line);
  1236.  
  1237.     IF (start_mark = 0) OR (end_mark = 0) THEN
  1238.         vi$info ("Bad range of lines!");
  1239.         RETURN (1);
  1240.     ENDIF;
  1241.  
  1242.     work_range := CREATE_RANGE (start_mark, end_mark, NONE);
  1243.  
  1244.     pos := MARK (NONE);
  1245.     POSITION (end_mark);
  1246.  
  1247.     IF (end_mark <> END_OF (CURRENT_BUFFER)) THEN
  1248.         MOVE_VERTICAL (1);
  1249.     ENDIF;
  1250.  
  1251.     IF (end_mark <> BEGINNING_OF (CURRENT_BUFFER)) THEN
  1252.         MOVE_HORIZONTAL (-1);
  1253.     ENDIF;
  1254.  
  1255.     whole_range := CREATE_RANGE (start_mark, MARK (NONE), NONE);
  1256.     POSITION (pos);
  1257.  
  1258.     !   If there is no command then move to the line indicated.
  1259.  
  1260.     rest := vi$rest_of_line (cmd, i);
  1261.     EDIT (rest, COLLAPSE);
  1262.     IF rest = "" THEN
  1263.         vi$old_place := MARK (NONE);
  1264.         POSITION (start_mark);
  1265.         RETURN (0);
  1266.     ENDIF;
  1267.  
  1268.     token_1 := vi$get_cmd_token (vi$_lower_chars, cmd, i);
  1269.  
  1270.     IF (vi$leading_str (token_1, "version") AND (LENGTH (token_1) > 2)) THEN
  1271.         vi$info (vi$_version);
  1272.         RETURN (0);
  1273.     ENDIF;
  1274.  
  1275.     IF (token_1 = "help") THEN
  1276.         RETURN (vi$do_help (vi$rest_of_line (cmd, i)));
  1277.     ENDIF;
  1278.  
  1279.     IF (token_1 = "show") THEN
  1280.         RETURN (vi$do_show (cmd, i));
  1281.     ENDIF;
  1282.  
  1283.     ! Check for substitution alias.
  1284.  
  1285.     IF (token_1 = "") AND (vi$parse_next_ch (i, cmd, "&")) THEN
  1286.         RETURN (vi$do_subs_alias (cmd, i, start_line, end_line, whole_range));
  1287.     ENDIF;
  1288.  
  1289.     IF (token_1 = "") AND (vi$parse_next_ch (i, cmd, "@")) THEN
  1290.         RETURN (vi$do_macro_buffer (cmd, i));
  1291.     ENDIF;
  1292.  
  1293.     IF (token_1 = "learn") THEN
  1294.         RETURN (vi$do_learn (cmd, i));
  1295.     ENDIF;
  1296.  
  1297.     IF (token_1 = "unlearn") THEN
  1298.         RETURN (vi$do_unlearn (cmd, i));
  1299.     ENDIF;
  1300.  
  1301.     IF (token_1 = "v") THEN
  1302.         RETURN (vi$do_global (cmd, i, "v"));
  1303.     ENDIF;
  1304.  
  1305.     IF (token_1 = "g") THEN
  1306.         RETURN (vi$do_global (cmd, i, "g"));
  1307.     ENDIF;
  1308.  
  1309.     IF (token_1 = "sh") OR (token_1 = "dcl") THEN
  1310.         RETURN (vi$spawn (0));
  1311.     ENDIF;
  1312.  
  1313.     IF (vi$leading_str (token_1, "unabbr") AND (LENGTH (token_1) > 4)) THEN
  1314.         RETURN (vi$do_unabbr (cmd, i));
  1315.     ENDIF;
  1316.  
  1317.     IF (vi$leading_str (token_1, "abbr") AND (LENGTH (token_1) > 3)) THEN
  1318.         RETURN (vi$do_abbr (cmd, i));
  1319.     ENDIF;
  1320.  
  1321.     IF (vi$leading_str (token_1, "edit")) OR (token_1 = "vi") THEN
  1322.         RETURN (vi$do_edit (cmd, i, token_1));
  1323.     ENDIF;
  1324.  
  1325.     IF (token_1 = "") THEN
  1326.         IF (vi$parse_next_ch (i, cmd, "!")) THEN
  1327.             RETURN (vi$do_subproc (cmd, i));
  1328.         ENDIF;
  1329.     ENDIF;
  1330.  
  1331.     IF (vi$leading_str (token_1, "copy")) THEN
  1332.         RETURN (vi$do_copy (cmd, i, whole_range, olen, start_line, end_line));
  1333.     ENDIF;
  1334.  
  1335.     IF (vi$leading_str (token_1, "move")) THEN
  1336.         RETURN (vi$do_move (cmd, i, whole_range, start_line, end_line));
  1337.     ENDIF;
  1338.  
  1339.     IF (vi$leading_str (token_1, "select")) AND (LENGTH (token_1) > 2) THEN
  1340.         RETURN (vi$do_select);
  1341.     ENDIF;
  1342.  
  1343.     IF (token_1 = "fill") THEN
  1344.         RETURN (vi$do_fill (cmd, i, whole_range, olen));
  1345.     ENDIF;
  1346.  
  1347.     IF ((LENGTH (token_1) > 1) AND (vi$leading_str (token_1, "upper") OR
  1348.                                     vi$leading_str (token_1, "lower") OR
  1349.                                     vi$leading_str (token_1, "invert"))) THEN
  1350.         RETURN (vi$do_case (token_1, whole_range));
  1351.     ENDIF;
  1352.  
  1353.     IF (token_1 = "s") THEN
  1354.         RETURN (vi$do_substitute (start_line, end_line, whole_range, i, cmd));
  1355.     ENDIF;
  1356.  
  1357.     IF (token_1 = "d") THEN
  1358.         RETURN (vi$do_delete (start_mark, whole_range, olen));
  1359.     ENDIF;
  1360.  
  1361.     ! Do the write file command.  You can write either a buffer, or a
  1362.     ! portion of one.
  1363.  
  1364.     IF (vi$leading_str (token_1, "write")) THEN
  1365.         RETURN (vi$do_write (cmd, i, no_spec, token_1, whole_range));
  1366.     ENDIF;
  1367.  
  1368.     IF (token_1 = "wq") THEN
  1369.         RETURN (vi$do_wq (cmd, i, no_spec, token_1, whole_range));
  1370.     ENDIF;
  1371.  
  1372.     IF (token_1 = "p") THEN
  1373.         RETURN (vi$do_print (start_mark, start_line, end_line));
  1374.     ENDIF;
  1375.  
  1376.     ! Read in a file to the current buffer.
  1377.  
  1378.     IF (vi$leading_str (token_1, "read")) THEN
  1379.         RETURN (vi$do_read (cmd, i, start_line, olen));
  1380.     ENDIF;
  1381.  
  1382.     IF (vi$leading_str (token_1, "file")) THEN
  1383.         RETURN (vi$do_file_ex (cmd, i));
  1384.     ENDIF;
  1385.  
  1386.     IF (vi$leading_str (token_1, "buffer")) THEN
  1387.         RETURN (vi$do_buffer (cmd, i, token_1));
  1388.     ENDIF;
  1389.  
  1390.     IF (token_1 = "so") THEN
  1391.         RETURN (vi$do_file (vi$rest_of_line (cmd, i), 1));
  1392.     ENDIF;
  1393.  
  1394.     IF (vi$leading_str (token_1, "messages")) THEN
  1395.         RETURN (vi$do_messages);
  1396.     ENDIF;
  1397.  
  1398.     IF (vi$leading_str (token_1, "delbuf")) THEN
  1399.         RETURN (vi$do_delbuf (cmd, i));
  1400.     ENDIF;
  1401.  
  1402.     IF (vi$leading_str (token_1, "xit")) THEN
  1403.         RETURN (vi$_ZZ (KEY_NAME ('Z')));
  1404.     ENDIF;
  1405.  
  1406.     IF (token_1 = "rew") THEN
  1407.         RETURN (vi$_first_file (vi$parse_next_ch (i, cmd, "!")));
  1408.     ENDIF;
  1409.  
  1410.     IF (vi$leading_str (token_1, "prev")) THEN
  1411.         RETURN (vi$_previous_file (vi$parse_next_ch (i, cmd, "!")));
  1412.     ENDIF;
  1413.  
  1414.     IF (vi$leading_str (token_1, "next")) THEN
  1415.         RETURN (vi$_next_file (vi$parse_next_ch (i, cmd, "!")));
  1416.     ENDIF;
  1417.  
  1418.     IF (token_1 = "tag") OR (token_1 = "ta") THEN
  1419.         token_1 := vi$parse_next_ch (i, cmd, "!");
  1420.         vi$skip_white (cmd, i);
  1421.         IF (vi$rest_of_line (cmd, i) = "") THEN
  1422.             RETURN (vi$do_tag (0));
  1423.         ELSE
  1424.             RETURN (vi$do_tag (vi$rest_of_line (cmd, i)));
  1425.         ENDIF;
  1426.     ENDIF;
  1427.  
  1428.     IF (token_1 = "map") THEN
  1429.         RETURN (vi$map_keys (cmd, i));
  1430.     ENDIF;
  1431.  
  1432.     IF (token_1 = "unmap") THEN
  1433.         RETURN (vi$unmap_keys (cmd, i));
  1434.     ENDIF;
  1435.  
  1436.     IF (token_1 = "set") OR (token_1 = "se") THEN
  1437.         RETURN (vi$set_commands (cmd, i));
  1438.     ENDIF;
  1439.  
  1440.     IF (token_1 = "tpu") THEN
  1441.         RETURN (vi$do_tpu (cmd, i, no_spec, whole_range));
  1442.     ENDIF;
  1443.  
  1444.     IF (token_1 = "cd") OR (token_1 = "chdir") THEN
  1445.         RETURN (vi$do_cd (cmd, i));
  1446.     ENDIF;
  1447.  
  1448.     ! Quit the current editor session.
  1449.  
  1450.     IF (vi$leading_str (token_1, "quit")) THEN
  1451.         RETURN (vi$do_quit (cmd, token_1));
  1452.     ENDIF;
  1453.  
  1454.     vi$info ("Unrecognized command! ("+cmd+")");
  1455.     RETURN (1);
  1456. ENDPROCEDURE;
  1457.  
  1458. !
  1459. !
  1460. !
  1461. PROCEDURE vi$do_unlearn (cmd, i)
  1462.     LOCAL
  1463.         keyn,
  1464.         com;
  1465.  
  1466.     vi$info ("Press the key you want to unlearn: ");
  1467.     keyn := vi$read_a_key;
  1468.  
  1469.     IF (keyn = F11) OR (ASCII (27) = ASCII (keyn)) THEN
  1470.         vi$info ("UNLEARN aborted!");
  1471.         RETURN (1);
  1472.     ENDIF;
  1473.  
  1474.     com := LOOKUP_KEY (keyn, COMMENT, vi$cmd_keys);
  1475.     IF (com <> "learn_sequence") THEN
  1476.         vi$info ("That key is not a learned KEY!");
  1477.         RETURN (1);
  1478.     ENDIF;
  1479.  
  1480.     UNDEFINE_KEY (keyn, vi$cmd_keys);
  1481. ENDPROCEDURE;
  1482.  
  1483. !
  1484. !
  1485. !
  1486. PROCEDURE vi$do_learn (cmd, i)
  1487.     LOCAL
  1488.         keyn,
  1489.         strg;
  1490.  
  1491.     vi$info ("Type KEY sequence, and press CTRL-R to remember sequence");
  1492.     vi$in_learn := 1;
  1493.     LEARN_BEGIN (EXACT);
  1494.     RETURN (1);
  1495. ENDPROCEDURE;
  1496.  
  1497. !
  1498. !   Remember the keystrokes that have been typed.
  1499. !
  1500. PROCEDURE vi$remember
  1501.  
  1502.     LOCAL
  1503.         key,
  1504.         keyn,
  1505.         com;
  1506.  
  1507.     ON_ERROR
  1508.         RETURN (1);
  1509.     ENDON_ERROR;
  1510.  
  1511.     IF (vi$in_learn = 0) THEN
  1512.         RETURN (0);
  1513.     ENDIF;
  1514.  
  1515. $$EOD$$
  1516.